package com.example.javapoet.demo.basic;

import com.squareup.javapoet.*;

import javax.lang.model.element.Modifier;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * JavaPoet基础示例 - 生成枚举类型
 */
public class BasicEnumGeneration {

    public static void main(String[] args) {
        // 生成一个简单的枚举
        generateSimpleEnum();
        
        // 生成一个带字段和方法的枚举
        generateEnumWithFieldsAndMethods();
        
        // 生成一个带抽象方法的枚举
        generateEnumWithAbstractMethods();
    }

    /**
     * 生成一个简单的枚举
     */
    public static void generateSimpleEnum() {
        // 创建枚举
        TypeSpec dayEnum = TypeSpec.enumBuilder("Day")
                .addModifiers(Modifier.PUBLIC)
                .addEnumConstant("MONDAY")
                .addEnumConstant("TUESDAY")
                .addEnumConstant("WEDNESDAY")
                .addEnumConstant("THURSDAY")
                .addEnumConstant("FRIDAY")
                .addEnumConstant("SATURDAY")
                .addEnumConstant("SUNDAY")
                .build();
        
        // 创建Java文件
        JavaFile javaFile = JavaFile.builder("com.example.model", dayEnum)
                .build();

        try {
            // 输出到控制台
            System.out.println("生成Day枚举:");
            javaFile.writeTo(System.out);
            
            // 输出到文件
            Path path = Paths.get("src/main/java");
            javaFile.writeTo(new File(path.toUri()));
            System.out.println("成功生成Day.java文件");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成一个带字段和方法的枚举
     */
    public static void generateEnumWithFieldsAndMethods() {
        // 创建字段
        FieldSpec codeField = FieldSpec.builder(int.class, "code")
                .addModifiers(Modifier.PRIVATE, Modifier.FINAL)
                .build();
        
        FieldSpec descriptionField = FieldSpec.builder(String.class, "description")
                .addModifiers(Modifier.PRIVATE, Modifier.FINAL)
                .build();
        
        // 创建构造函数
        MethodSpec constructor = MethodSpec.constructorBuilder()
                .addParameter(int.class, "code")
                .addParameter(String.class, "description")
                .addStatement("this.code = code")
                .addStatement("this.description = description")
                .build();
        
        // 创建getter方法
        MethodSpec getCodeMethod = MethodSpec.methodBuilder("getCode")
                .addModifiers(Modifier.PUBLIC)
                .returns(int.class)
                .addStatement("return code")
                .build();
        
        MethodSpec getDescriptionMethod = MethodSpec.methodBuilder("getDescription")
                .addModifiers(Modifier.PUBLIC)
                .returns(String.class)
                .addStatement("return description")
                .build();
        
        // 创建静态方法
        MethodSpec fromCodeMethod = MethodSpec.methodBuilder("fromCode")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                .returns(ClassName.get("com.example.model", "StatusCode"))
                .addParameter(int.class, "code")
                .beginControlFlow("for ($T status : values())", ClassName.get("com.example.model", "StatusCode"))
                .beginControlFlow("if (status.getCode() == code)")
                .addStatement("return status")
                .endControlFlow()
                .endControlFlow()
                .addStatement("throw new $T($S + code)", IllegalArgumentException.class, "Unknown status code: ")
                .build();
        
        // 创建枚举
        TypeSpec statusCodeEnum = TypeSpec.enumBuilder("StatusCode")
                .addModifiers(Modifier.PUBLIC)
                .addField(codeField)
                .addField(descriptionField)
                .addMethod(constructor)
                .addMethod(getCodeMethod)
                .addMethod(getDescriptionMethod)
                .addMethod(fromCodeMethod)
                .addEnumConstant("OK", TypeSpec.anonymousClassBuilder("$L, $S", 200, "OK")
                        .build())
                .addEnumConstant("CREATED", TypeSpec.anonymousClassBuilder("$L, $S", 201, "Created")
                        .build())
                .addEnumConstant("ACCEPTED", TypeSpec.anonymousClassBuilder("$L, $S", 202, "Accepted")
                        .build())
                .addEnumConstant("BAD_REQUEST", TypeSpec.anonymousClassBuilder("$L, $S", 400, "Bad Request")
                        .build())
                .addEnumConstant("UNAUTHORIZED", TypeSpec.anonymousClassBuilder("$L, $S", 401, "Unauthorized")
                        .build())
                .addEnumConstant("FORBIDDEN", TypeSpec.anonymousClassBuilder("$L, $S", 403, "Forbidden")
                        .build())
                .addEnumConstant("NOT_FOUND", TypeSpec.anonymousClassBuilder("$L, $S", 404, "Not Found")
                        .build())
                .addEnumConstant("INTERNAL_SERVER_ERROR", TypeSpec.anonymousClassBuilder("$L, $S", 500, "Internal Server Error")
                        .build())
                .build();
        
        // 创建Java文件
        JavaFile javaFile = JavaFile.builder("com.example.model", statusCodeEnum)
                .build();

        try {
            // 输出到控制台
            System.out.println("\n生成StatusCode枚举:");
            javaFile.writeTo(System.out);
            
            // 输出到文件
            Path path = Paths.get("src/main/java");
            javaFile.writeTo(new File(path.toUri()));
            System.out.println("成功生成StatusCode.java文件");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成一个带抽象方法的枚举
     */
    public static void generateEnumWithAbstractMethods() {
        // 创建抽象方法
        MethodSpec applyMethod = MethodSpec.methodBuilder("apply")
                .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
                .returns(double.class)
                .addParameter(double.class, "value")
                .build();
        
        // 创建枚举常量，每个常量都实现抽象方法
        TypeSpec.Builder operationEnumBuilder = TypeSpec.enumBuilder("Operation")
                .addModifiers(Modifier.PUBLIC)
                .addMethod(applyMethod);
        
        // 添加ADD枚举常量
        operationEnumBuilder.addEnumConstant("ADD", TypeSpec.anonymousClassBuilder("")
                .addMethod(MethodSpec.methodBuilder("apply")
                        .addAnnotation(Override.class)
                        .addModifiers(Modifier.PUBLIC)
                        .returns(double.class)
                        .addParameter(double.class, "value")
                        .addStatement("return value + value")
                        .build())
                .build());
        
        // 添加SUBTRACT枚举常量
        operationEnumBuilder.addEnumConstant("SUBTRACT", TypeSpec.anonymousClassBuilder("")
                .addMethod(MethodSpec.methodBuilder("apply")
                        .addAnnotation(Override.class)
                        .addModifiers(Modifier.PUBLIC)
                        .returns(double.class)
                        .addParameter(double.class, "value")
                        .addStatement("return value - value")
                        .build())
                .build());
        
        // 添加MULTIPLY枚举常量
        operationEnumBuilder.addEnumConstant("MULTIPLY", TypeSpec.anonymousClassBuilder("")
                .addMethod(MethodSpec.methodBuilder("apply")
                        .addAnnotation(Override.class)
                        .addModifiers(Modifier.PUBLIC)
                        .returns(double.class)
                        .addParameter(double.class, "value")
                        .addStatement("return value * value")
                        .build())
                .build());
        
        // 添加DIVIDE枚举常量
        operationEnumBuilder.addEnumConstant("DIVIDE", TypeSpec.anonymousClassBuilder("")
                .addMethod(MethodSpec.methodBuilder("apply")
                        .addAnnotation(Override.class)
                        .addModifiers(Modifier.PUBLIC)
                        .returns(double.class)
                        .addParameter(double.class, "value")
                        .beginControlFlow("if (value == 0)")
                        .addStatement("throw new $T($S)", ArithmeticException.class, "Division by zero")
                        .endControlFlow()
                        .addStatement("return value / value")
                        .build())
                .build());
        
        // 创建枚举
        TypeSpec operationEnum = operationEnumBuilder.build();
        
        // 创建Java文件
        JavaFile javaFile = JavaFile.builder("com.example.model", operationEnum)
                .build();

        try {
            // 输出到控制台
            System.out.println("\n生成Operation枚举:");
            javaFile.writeTo(System.out);
            
            // 输出到文件
            Path path = Paths.get("src/main/java");
            javaFile.writeTo(new File(path.toUri()));
            System.out.println("成功生成Operation.java文件");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}